package com.example.rtsp.service.impl;

import com.example.rtsp.service.FFmpegService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import java.io.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

/**
 * @Author: 杜科璇
 * @Description: FFmpeg服务
 * @Date: 2025/9/5 18:41
 * @Version: 1.0
 */

@Service
public class FFmpegServiceImpl_ok implements FFmpegService {

    // 移除对VideoStreamHandler的直接依赖
    private Consumer<byte[]> frameConsumer;
    private static final int MAX_BUFFER_SIZE = 1024 * 1024; // 1MB



    private static final Logger logger = LoggerFactory.getLogger(FFmpegService.class);

    @Value("${rtsp.url}")
    private String rtspUrl;

    @Value("${ffmpeg.fps:15}")
    private int fps;

    @Value("${ffmpeg.width:1280}")
    private int width;

    @Value("${ffmpeg.height:720}")
    private int height;

    private final AtomicBoolean running = new AtomicBoolean(false);
    private Process ffmpegProcess;
    private ExecutorService executorService;

    @Override
    // 通过setter方法注入
    public void setFrameConsumer(Consumer<byte[]> frameConsumer) {
        this.frameConsumer = frameConsumer;
    }
    public void start() {
        if (running.get()) return;

        running.set(true);
        executorService = Executors.newSingleThreadExecutor();
        executorService.execute(this::captureFrames);

        logger.info("FFmpeg服务已启动，RTSP源: {}", rtspUrl);
    }

    @PreDestroy
    @Override
    public void stop() {
        running.set(false);
        if (ffmpegProcess != null) {
            ffmpegProcess.destroy();
        }
        if (executorService != null) {
            executorService.shutdown();
        }
        logger.info("FFmpeg服务已停止");
    }

    // 处理FFmpeg输出流
    private void captureFrames() {
        try {
            String[] cmd = buildFFmpegCommand();
            ffmpegProcess = new ProcessBuilder(cmd).start();

            // 直接读取二进制流
            readBinaryStream(ffmpegProcess.getInputStream());

            // 错误流可以继续使用文本方式读取
            new Thread(() -> {
                try (InputStream errorStream = ffmpegProcess.getErrorStream()) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = errorStream.read(buffer)) != -1) {
                        logger.debug("FFmpeg: {}", new String(buffer, 0, bytesRead));
                    }
                } catch (IOException e) {
                    logger.debug("错误流读取结束", e);
                }
            }).start();

            ffmpegProcess.waitFor();
        } catch (IOException | InterruptedException e) {
            logger.error("FFmpeg处理异常", e);
        } finally {
            if (running.get()) {
                logger.warn("FFmpeg进程异常退出，尝试重启...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                captureFrames();
            }
        }
    }

    // 处理二进制流
    private void readBinaryStream(InputStream inputStream) {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
//        byte[] chunk = new byte[4096]; // 4KB缓冲区
        byte[] chunk = new byte[8192]; // 8KB缓冲区
        int bytesRead;

        try {
            // 循环读取数据
            while (running.get() && (bytesRead = inputStream.read(chunk)) != -1) {
                buffer.write(chunk, 0, bytesRead);

                // 限制缓冲区大小，防止内存溢出
                if (buffer.size() > MAX_BUFFER_SIZE) {
                    buffer.reset();
                    logger.warn("缓冲区过大，已重置");
                }

                byte[] data = buffer.toByteArray();

                // 查找JPEG帧边界
                int start = findJpegStart(data);
                while (start >= 0) {
                    int end = findJpegEnd(data, start);
                    if (end > start) {
                        byte[] frame = new byte[end - start + 2];
                        System.arraycopy(data, start, frame, 0, frame.length);

                        // 处理帧
                        if (frameConsumer != null) {
                            frameConsumer.accept(frame);
                        }

                        // 移除已处理的数据
                        byte[] remaining = new byte[data.length - end - 2];
                        System.arraycopy(data, end + 2, remaining, 0, remaining.length);
                        data = remaining;
                        start = findJpegStart(data);
                    } else {
                        break;
                    }
                }

                buffer.reset();
                if (data.length > 0) {
                    buffer.write(data);
                }
                // 添加短暂休眠以避免过度占用CPU
                Thread.yield();
            }
        } catch (IOException e) {
            logger.error("读取FFmpeg输出流失败", e);
        }
    }

    // 寻找JPEG帧的开始位置
    private int findJpegStart(byte[] data) {
        for (int i = 0; i < data.length - 1; i++) {
            if (data[i] == (byte)0xFF && data[i+1] == (byte)0xD8) {
                return i;
            }
        }
        return -1;
    }

    // 查找JPEG帧的结束位置

    private int findJpegEnd(byte[] data, int start) {
        for (int i = start + 2; i < data.length - 1; i++) {
            if (data[i] == (byte)0xFF && data[i+1] == (byte)0xD9) {
                return i;
            }
        }
        return -1;
    }

//    private String[] buildFFmpegCommand() {
//        return new String[] {
//                "ffmpeg",
//                "-rtsp_transport", "tcp",
//                "-i", rtspUrl,
//                "-f", "image2",
//                "-c:v", "mjpeg",
//                "-q:v", "3",
//                "-vf", String.format("fps=%d,scale=%d:%d", fps, width, height),
//                "-update", "1",
//                "pipe:1"
//        };
//    }

    private String[] buildFFmpegCommand() {
        return new String[] {
                "ffmpeg",
                "-rtsp_transport", "tcp",
                "-i", rtspUrl,
                "-f", "image2",
                "-c:v", "mjpeg",
                "-q:v", "3",
                "-vf", String.format("fps=%d,scale=%d:%d", fps, width, height),
                "-update", "1",
                "-probesize", "32768",      // 减小探测大小
                "-analyzeduration", "1000000", // 减少分析时间(1秒)
                "-fflags", "nobuffer",      // 禁用缓冲
//                "-flags", "low_delay",      // 启用低延迟标志
                "pipe:1"
        };
    }


}